home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / irsim-ca.2 / irsim-ca / irsim-cap-9.2 / src / irsim / newrstep.c < prev    next >
C/C++ Source or Header  |  1993-01-15  |  41KB  |  1,615 lines

  1. /* 
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     ********************************************************************* 
  13.  */
  14.  
  15. /* 
  16.  * Event-driven timing simulation step for irsim.
  17.  * 
  18.  * Use diamond shape region in R-V plane for dc voltage computation.
  19.  * Use 2-pole 1-zero model for pure charge sharing delay calculations.
  20.  * Use 2-pole zero-at-origin model for driven spike analysis.
  21.  * Details of the models can be found in Chorng-Yeong Chu's thesis:
  22.  * "Improved Models for Switch-Level Simulation" also available as a
  23.  * Stanford Technical Report CSL-TR-88-368.
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <math.h>
  28. #include "defs.h"
  29. #include "net.h"
  30. #include "globals.h"
  31. #ifdef DO_CACHE
  32. #include "cache.h"
  33. #endif
  34.  
  35.  
  36. #define    SMALL        1E-15        /* A small number */
  37. #define    LARGE        1E15        /* A large number */
  38. #define    LIMIT        1E8        /* R > LIMIT are considered infinite */
  39. #define    NP_RATIO    0.7        /* nmos-pmos ratio for spike analysis */
  40.  
  41.  
  42. #define    MIN( a, b )        ((a < b) ? a : b)
  43. #define    MAX( a, b )        ((a > b) ? a : b)
  44.  
  45.  
  46.     /* combine 2 resistors in parallel */
  47. #define    COMBINE( R1, R2 )    ( (R1) * (R2) / ( (R1) + (R2) ) )
  48.     /* combine 2 resistors in parallel, watch out for zero resistance */
  49. #define    COMBINE_R( A, B )    ( ((A) + (B) <= SMALL) ? 0 : COMBINE( A, B ) )
  50.  
  51. #define    IsWatched( N )        ( (N)->nflags & WATCHED )
  52. #define    SetDebug( FL, N )    \
  53.     ( ((debug & (FL)) == (FL) and IsWatched( N )) ? 1 : 0 )
  54.  
  55.         /* flags used in thevenin structure */
  56. #define    T_DEFINITE    0x01    /* set for a definite rooted path        */
  57. #define    T_UDELAY    0x02    /* set if user specified delay encountered  */
  58. #define    T_SPIKE        0x04    /* set if charge-sharing spike possible        */
  59. #define    T_DRIVEN    0x08    /* set if this branch is driven            */
  60. #define    T_REFNODE    0x10    /* set for the reference node in pure c-s   */
  61. #define    T_XTRAN        0x20    /* set if connecting through an X trans.    */
  62. #define    T_INT        0x40    /* set if we should consider input slope    */
  63. #define    T_DOMDRIVEN    0x80    /* set if branch driven to dominant voltage */
  64.  
  65. public    int       tunitdelay = 0;    /* if <> 0, all transitions take
  66.                      * 'tunitdelay' DELAY-units */
  67. public    int       tdecay = 0;        /* if <> 0, undriven nodes decay to 
  68.                      * X after 'tdecay' DELAY-units */
  69. public    char      withdriven;        /* TRUE if stage is driven by
  70.                      *  some input */
  71.  
  72.  
  73. typedef    struct
  74.   {
  75.     double  min;
  76.     double  max;
  77.   } Range;
  78.  
  79.     /* Parameters gathered during a tree walk */
  80.         /* resists are in ohms, caps in pf */
  81. typedef struct thevenin
  82.   {
  83.     union
  84.       {
  85.     Thev  t;
  86.     nptr  n;
  87.       } link;            /* links these structures together        */
  88.     int      flags;        /* flags defined above                */
  89.     Range    Clow;        /* capacitance charged low            */
  90.     Range    Chigh;        /* capacitance charged high            */
  91.     Range    Rup;        /* resistance pulling up to Vdd            */
  92.     Range    Rdown;        /* resistance pulling down to GND        */
  93.     Range    Req;        /* resist. of present (parallel) xtor(s)    */
  94.     Range    V;            /* normalized voltage range (0-1)        */
  95.     double   Rmin;        /* minimum resistance to any driver        */
  96.     double   Rdom;        /* minimum resistance to dominant driver    */
  97.     double   Rmax;        /* maximum resistance to dominant driver    */
  98.     double   Ca;        /* Adjusted non-switching capacitance         */
  99.     double   Cd;        /* Adjusted total capacitance            */
  100.     double   tauD;        /* Elmore delay    (psec)                */
  101.     double   tauA;        /* 1st order time-constant (psec)        */
  102.     double   tauP;        /* 2nd order time-constant (psec)        */
  103.     double   Tin;        /* input transition = (input_tau) * Rin        */
  104.     short    tplh;        /* user specified low->high delay (DELTA)   */
  105.     short    tphl;        /* user specified high->low delay (DELTA)   */
  106.     char     final;        /* steady-state value calculated (H, L, X)  */
  107.     char     tau_done;        /* if tau calculated, == dominant voltage   */
  108.     char     taup_done;        /* if tauP calculated, == dominant voltage  */
  109.   } thevenin;
  110.  
  111.  
  112. typedef struct            /* one for each possible dominant voltage */
  113.   {
  114.     nptr  nd;            /* list of nodes driven to this potential */
  115.     int   spike;        /* TRUE if this pot needs spike analysis */
  116.   } Dominant;
  117.  
  118.  
  119. typedef struct
  120.   {
  121.     double  ch_delay;        /* charging delay */
  122.     double  dr_delay;        /* driven delay */
  123.     float   peak;        /* spike peak */
  124.     int     charge;        /* spike charge */
  125.   } SpikeRec, *pspk;
  126.  
  127.  
  128. private    Thev      thev_free = NULL;    /* Free list of thev structures */
  129. private    int       inc_level;        /* 1 if debug and node is watched */
  130. private    Dominant  dom_pot[ N_POTS ];    /* dominant voltage structure */
  131.  
  132. private    thevenin  init_thev;        /* pre-initialized thevenin structs */
  133. private    thevenin  input_thev[ N_POTS ];
  134.  
  135.  
  136.     /* forward references */
  137. private    void    scheduleDriven(), schedulePureCS(), UndoConnList();
  138. private    void    parallel_op(), CleanEvents(), EnqueDecay();
  139. private    int    ComputeDC();
  140. private    Thev    get_dc_val(), series_op(), get_tau();
  141. private    double    get_tauP();
  142. private    pspk    ComputeSpike();
  143. private    void    print_dc(), print_fval(), print_tau(), print_taup();
  144. private    void    print_final(), print_spike(), print_spk();
  145.  
  146.  
  147. public void linear_model( n )
  148.   nptr    n;
  149.   {
  150.     int  i, changes;
  151.  
  152.     nevals++;
  153.  
  154.     for( i = LOW; i <= HIGH; i++ ) 
  155.     dom_pot[i].nd = NULL, dom_pot[i].spike = FALSE;
  156.  
  157.     if( n->nflags & VISITED )
  158.     BuildConnList( n );
  159.  
  160.     changes = ComputeDC( n );
  161.  
  162.     if( not changes )
  163.     CleanEvents( n );
  164.     else if( withdriven )
  165.     scheduleDriven();
  166.     else
  167.     schedulePureCS( n );
  168.  
  169.     if( tdecay != 0 and not withdriven )
  170.     EnqueDecay( n );
  171.  
  172.     UndoConnList( n );
  173.   }
  174.  
  175.  
  176. private void CleanEvents( n )
  177.   register nptr  n;
  178.   {
  179.     register evptr  ev;
  180.  
  181.     do
  182.       {
  183.     while( (ev = n->events) != NULL )
  184.         PuntEvent( n, ev );
  185.       }
  186.     while( (n = n->nlink) != NULL );
  187.   }
  188.  
  189.  
  190. private void EnqueDecay( n )
  191.   register nptr  n;
  192.   {
  193.     register evptr  ev;
  194.  
  195.     do
  196.       {
  197.     ev = n->events;
  198.     if( (ev == NULL) ? n->npot : ev->eval != X )
  199.       {
  200.         if( (debug & DEBUG_EV) and IsWatched( n ) )
  201.         lprintf( stdout, "  decay transition for %s @ %.1fns\n",
  202.           pnode( n ), d2ns( cur_delta + tdecay ) );
  203.         enqueue_event( n, DECAY, (long) tdecay, (long) tdecay );
  204.      }
  205.     n = n->nlink;
  206.       }
  207.     while( n != NULL );
  208.   }
  209.  
  210.  
  211. private void UndoConnList( n )
  212.   register nptr  n;
  213.   {
  214.     register nptr  next;
  215.     register lptr  l;
  216.     register tptr  t;
  217. #ifdef CL_STATS
  218.     register int   num_trans = 0;
  219.  
  220.     for( next = n; next != NULL; next = next->nlink )
  221.       {
  222.     for( l = next->nterm; l != NULL; l = l->next )
  223.       {
  224.         t = l->xtor;
  225.         if( t->state != OFF )
  226.         t->tflags |= CROSSED;
  227.       }
  228.       }
  229. #endif CL_STATS
  230.  
  231.     do
  232.       {
  233.     next = n->nlink;
  234.     n->nlink = NULL;
  235.  
  236.     n->n.thev->link.t = thev_free;
  237.     thev_free = n->n.thev;
  238.  
  239.     for( l = n->nterm; l != NULL; l = l->next )
  240.       {
  241.         t = l->xtor;
  242.         if( t->state == OFF )
  243.         continue;
  244.         
  245. #ifdef CL_STATS
  246.         if( t->tflags & CROSSED )
  247.         num_trans ++;
  248. #endif CL_STATS
  249.         if( not( t->tflags & (PBROKEN | BROKEN) ) )
  250.           {
  251.         register Thev  r;
  252.  
  253.         if( (r = t->scache.r) != NULL )
  254.           {
  255.             r->link.t = thev_free;
  256.             thev_free = r;
  257.           }
  258.         if( (r = t->dcache.r) != NULL )
  259.           {
  260.             r->link.t = thev_free;
  261.             thev_free = r;
  262.           }
  263.           }
  264.         t->scache.r = t->dcache.r = NULL;
  265.         t->tflags &= ~(CROSSED | BROKEN | PBROKEN | PARALLEL);
  266.       }
  267.       }
  268.     while( (n = next) != NULL );
  269.  
  270. #ifdef CL_STATS
  271.     RecordConnList( num_trans );
  272. #endif CL_STATS
  273.   }
  274.  
  275.  
  276. /* 
  277.  * Schedule the final value for node 'nd'.  Check to see if this final value
  278.  * invalidates other events.  Since this event has more recent information
  279.  * regarding the state of the network, delete transitions scheduled to come
  280.  * after it.  Zero-delay transitions are avoided by turning them into unit
  281.  * delays (1 delta).  Events scheduled to occur at the same time as this event
  282.  * and driving the node to the same value are not punted.
  283.  * Finally, before scheduling the final value, check that it is different
  284.  * from the previously calculated value for the node.
  285.  */
  286. private void QueueFVal( nd, fval, tau, delay )
  287.   nptr    nd;
  288.   int     fval;
  289.   double  tau, delay;
  290.   {
  291.     register evptr  ev;
  292.     register Ulong  delta;
  293.     int             queued = 0;
  294.  
  295.     delta = cur_delta + (Ulong) ps2d( delay );
  296.     if( delta == cur_delta )            /* avoid zero delay */
  297.     delta++;
  298.  
  299.     while( (ev = nd->events) != NULL and ev->ntime >= delta )
  300.       {
  301.     if( ev->ntime == delta and ev->eval == fval )
  302.         break;
  303.     PuntEvent( nd, ev );
  304.       }
  305.  
  306.     delta -= cur_delta;
  307.  
  308.     if( fval != ((ev == NULL) ? nd->npot : ev->eval) )
  309.       {
  310.     enqueue_event( nd, fval, (long) delta, (long) ps2d( tau ) );
  311.     queued = 1;
  312.       }
  313.  
  314.     if( (debug & DEBUG_EV) and IsWatched( nd ) )
  315.     print_final( nd, queued, tau, delta );
  316.   }
  317.  
  318.  
  319. private void QueueSpike( nd, spk )
  320.   nptr  nd;
  321.   pspk  spk;
  322.   {
  323.     register evptr  ev;
  324.     register Ulong  ch_delta, dr_delta;
  325.  
  326.     while( (ev = nd->events) != NULL )
  327.     PuntEvent( nd, ev );
  328.  
  329.     if( spk == NULL )        /* no spike, just punt events */
  330.       {
  331.     return;
  332.       }
  333.  
  334.     ch_delta = (Ulong) ps2d( spk->ch_delay );
  335.     dr_delta = (Ulong) ps2d( spk->dr_delay );
  336.  
  337.     if( ch_delta == 0 )
  338.     ch_delta = 1;
  339.     if( dr_delta == 0 )
  340.     dr_delta = 1;
  341.  
  342.     if( (debug & DEBUG_EV) and IsWatched( nd ) )
  343.     print_spike( nd, spk, ch_delta, dr_delta );
  344.  
  345.     if( dr_delta <= ch_delta )        /* no zero delay spikes, done */
  346.       {
  347.     return;
  348.       }
  349.  
  350.     /* enqueue spike and final value events */
  351.     enqueue_event( nd, (int) spk->charge, (long) ch_delta, (long) ch_delta );
  352.     enqueue_event( nd, (int) nd->npot, (long) dr_delta, (long) ch_delta );
  353.   }
  354.  
  355.  
  356. private void scheduleDriven()
  357.   {
  358.     register nptr  nd;
  359.     register Thev  r;
  360.     int            dom;
  361.     double         tau, delay;
  362.  
  363.     for( dom = 0; dom < N_POTS; dom++ )
  364.       {
  365.     for( nd = dom_pot[ dom ].nd; nd != NULL; nd = r->link.n )
  366.       {
  367.         inc_level = SetDebug( DEBUG_TAU | DEBUG_TW, nd );
  368.  
  369.         r = get_tau( nd, (tptr) NULL, dom, inc_level );
  370.  
  371.         if( inc_level == 0 and SetDebug( DEBUG_TAU, nd ) )
  372.         print_tau( nd, r, -1 );
  373.  
  374.         r->tauA = r->Rdom * r->Ca;
  375.         r->tauD = r->Rdom * r->Cd;
  376.  
  377.         if( r->flags & T_SPIKE )        /* deal with these later */
  378.         continue;
  379.  
  380.         if( nd->npot == r->final )        /* no change, just punt */
  381.           {
  382.         evptr  ev;
  383.  
  384.         while( (ev = nd->events) != NULL )
  385.             PuntEvent( nd, ev );
  386.         continue;
  387.           }
  388.         else if( tunitdelay )
  389.           {
  390.         delay = tunitdelay;
  391.         tau = 0.0;
  392.           }
  393.         else if( r->flags & T_UDELAY )
  394.           {
  395.         switch( r->final )
  396.           {
  397.             case LOW :    tau = d2ps( r->tphl );            break;
  398.             case HIGH :    tau = d2ps( r->tplh );            break;
  399.             case X :    tau = d2ps( MIN( r->tphl, r->tplh ) );    break;
  400.           }
  401.         delay = tau;
  402.           }
  403.         else
  404.           {
  405.         if( r->final == X )
  406.             tau = r->Rmin * r->Ca;
  407.         else if( r->flags & T_DEFINITE )
  408.             tau = r->Rmax * r->Ca;
  409.         else
  410.             tau = r->Rdom * r->Ca;
  411.  
  412.         if( (r->flags & T_INT) and r->Tin > 0.5 )
  413.             delay = sqrt( tau * tau + d2ps( r->Tin ) * r->Ca );
  414.         else
  415.             delay = tau;
  416.           }
  417.  
  418.         QueueFVal( nd, (int) r->final, tau, delay );
  419.       }
  420.  
  421.     if( dom_pot[ dom ].spike )
  422.       {
  423.         pspk  spk;
  424.  
  425.         for( nd = dom_pot[ dom ].nd; nd != NULL; nd = nd->n.thev->link.n )
  426.           {
  427.         r = nd->n.thev;
  428.         if( not (r->flags & T_SPIKE) )
  429.             continue;
  430.  
  431.         inc_level = SetDebug( DEBUG_TAUP | DEBUG_TW, nd );
  432.  
  433.         r->tauP = get_tauP( nd, (tptr) NULL, dom, inc_level );
  434.  
  435.         r->tauP *= r->Rdom / r->tauA;
  436.  
  437.         QueueSpike( nd, ComputeSpike( nd, r, dom ) );
  438.           }
  439.       }
  440.       }
  441.   }
  442.  
  443.  
  444. private void schedulePureCS( nlist )
  445.   nptr  nlist;
  446.   {
  447.     register nptr  nd;
  448.     register Thev  r;
  449.     int            dom;
  450.     double         taup, tau, delay;
  451.  
  452.     r = nlist->n.thev;
  453.  
  454.     dom = r->final;
  455.     r->flags |= T_REFNODE;
  456.  
  457.     taup = 0.0;
  458.     for( nd = nlist; nd != NULL; nd = nd->nlink )
  459.       {
  460.     inc_level = SetDebug( DEBUG_TAU | DEBUG_TW, nd );
  461.  
  462.     r = get_tau( nd, (tptr) NULL, dom, inc_level );
  463.  
  464.     r->tauD = r->Rdom * r->Ca;
  465.  
  466.     switch( dom )
  467.       {
  468.         case LOW :
  469.         r->tauA = r->Rdom * ( r->Ca - r->Cd * r->V.max );
  470.         break;
  471.         case HIGH : 
  472.         r->tauA = r->Rdom * ( r->Cd * ( 1 - r->V.min ) - r->Ca );
  473.         break;
  474.         case X :            /* approximate Vf = 0.5 */
  475.         r->tauA = r->Rdom * ( r->Ca - r->Cd * 0.5 ); 
  476.         break;
  477.       }
  478.     taup += r->tauA * nd->ncap;
  479.       }
  480.  
  481.     r = nlist->n.thev;
  482.     taup = taup / (r->Clow.min + r->Chigh.max);        /* tauP = tauP / CT */
  483.  
  484.     for( nd = nlist; nd != NULL; nd = nd->nlink )
  485.       {
  486.     r = nd->n.thev;
  487.     if( r->final == nd->npot )        /* no change, no delay */
  488.         delay = tau = 0.0;
  489.     else
  490.       {
  491.         switch( r->final )
  492.           {
  493.         case LOW   : tau = (r->tauA - taup) / (1.0 - r->V.max);    break;
  494.         case HIGH  : tau = (taup - r->tauA) / r->V.min;        break;
  495.         case X     : tau = (r->tauA - taup) * 2.0;        break;
  496.           }
  497.         if( tau < 0.0 )
  498.         tau = 0.0;
  499.         if( tunitdelay )
  500.         delay = tunitdelay, tau = 0.0;
  501.         else
  502.         delay = tau;
  503.       }
  504.  
  505.     QueueFVal( nd, (int) r->final, tau, delay );
  506.       }
  507.   }
  508.  
  509.  
  510. /*
  511.  * Compute the final value for each node on the connection list.
  512.  * This routine will update V.min and V.max and add the node to the
  513.  * corresponding dom_driver entry.  Return TRUE if any node changes value.
  514.  */
  515. private int ComputeDC( nlist )
  516.   nptr  nlist;
  517.   {
  518.     register nptr  this, next;
  519.     register Thev  r;
  520.     int            anyChange = FALSE;
  521.  
  522.     for( this = nlist; this != NULL; this = this->nlink )
  523.       {
  524.     inc_level = SetDebug( DEBUG_DC | DEBUG_TW, this );
  525.  
  526.     this->n.thev = r = get_dc_val( this, (tptr) NULL, inc_level );
  527.  
  528.     if( withdriven )
  529.       {
  530.         if( r->Rdown.min >= LIMIT )
  531.         r->V.min = 1;
  532.         else
  533.         r->V.min = r->Rdown.min / ( r->Rdown.min + r->Rup.max );
  534.         if( r->Rup.min >= LIMIT )
  535.         r->V.max = 0;
  536.         else
  537.         r->V.max = r->Rdown.max / ( r->Rdown.max + r->Rup.min );
  538.       }
  539.     else        /* use charge/total charge if undriven */
  540.       {
  541.         r->V.min = r->Chigh.min / ( r->Chigh.min + r->Clow.max );
  542.         r->V.max = r->Chigh.max / ( r->Chigh.max + r->Clow.min );
  543.       }
  544.  
  545.     if( r->V.min >= this->vhigh )
  546.         r->final = HIGH;
  547.     else if( r->V.max <= this->vlow )
  548.         r->final = LOW;
  549.     else
  550.         r->final = X;
  551.  
  552.     if( withdriven )
  553.       {
  554.         /*
  555.          * if driven and indefinite, driven value must equal 
  556.          * charging value otherwise the final value is X
  557.          */
  558.         if( r->final != X and not (r->flags & T_DEFINITE) )
  559.           {
  560.         char  cs_val;
  561.  
  562.         if( r->Chigh.min >= this->vhigh * (r->Chigh.min + r->Clow.max) )
  563.             cs_val = HIGH;
  564.         else if( r->Chigh.max <= this->vlow * (r->Chigh.max + r->Clow.min) )
  565.             cs_val = LOW;
  566.         else
  567.             cs_val = X;            /* always X */
  568.  
  569.         if( cs_val != r->final )
  570.             r->final = X;
  571.           }
  572.  
  573.         r->link.n = dom_pot[ r->final ].nd;        /* add it to list */
  574.         dom_pot[ r->final ].nd = this;
  575.  
  576.         /* possible spike if no transition and opposite charge exists */
  577.         if( r->final == this->npot and (
  578.           (r->final == LOW and r->Chigh.min > SMALL) or
  579.           (r->final == HIGH and r->Clow.min > SMALL) ) )
  580.           {
  581.         r->flags |= T_SPIKE;
  582.         dom_pot[ r->final ].spike = TRUE;
  583.         anyChange = TRUE;
  584.           }
  585.       }
  586.  
  587.     if( r->final != this->npot )
  588.         anyChange = TRUE;
  589.  
  590.     if( SetDebug( DEBUG_DC, this ) )
  591.         print_fval( this, r );
  592.       }
  593.     return( anyChange );
  594.   }
  595.  
  596.  
  597.  
  598. #define NEW_THEV( T )                        \
  599.   {                                \
  600.     if( ((T) = thev_free) == NULL )                \
  601.     (T) = (Thev) MallocList( sizeof( thevenin ), 1 );    \
  602.     thev_free = T->link.t;                    \
  603.   }
  604.  
  605.  
  606. /*
  607.  * Compute the parametes used to calculate the final value (Chigh, Clow,
  608.  * Rup, Rdown) by doing a depth-first traversal of the tree rooted at node
  609.  * 'n'.  The traversal is done by a recursive walk through the tree. Note that
  610.  * the stage is already a simple tree; loops are broken by BuildConnList.  As
  611.  * a side effect also compute Req of the present transistor and all other
  612.  * transistors in parallel with it, and any specified user delays.
  613.  * The parameters are:
  614.  *
  615.  * n      : the node whose dc parameters we want.
  616.  * tran   : the transistor that leads to 'n' (NULL if none).
  617.  * level  : level of recursion if we are debugging this node, else 0.
  618.  */
  619. private Thev get_dc_val( n, tran, level )
  620.   nptr  n;
  621.   tptr  tran;
  622.   int   level;
  623.   {
  624.     register lptr  l;
  625.     register tptr  t;
  626.     register nptr  other;
  627.     register Thev  r;
  628.     Thev           cache, *pcache;
  629.  
  630.     NEW_THEV( r );
  631.  
  632.     if( n->nflags & INPUT )
  633.       {
  634.     *r = input_thev[ n->npot ];
  635.     return( r );
  636.       }
  637.  
  638.     *r = init_thev;
  639.     switch( n->npot )
  640.       {
  641.     case LOW :   r->Clow.min = r->Clow.max = n->ncap;    break;
  642.     case X :     r->Clow.max = r->Chigh.max = n->ncap;    break;
  643.     case HIGH :  r->Chigh.min = r->Chigh.max = n->ncap;    break;
  644.       }
  645.  
  646.     for( l = n->nterm; l != NULL; l = l->next )
  647.       {
  648.     t = l->xtor;
  649.  
  650.     /* ignore path going back or through a broken loop */
  651.     if( t == tran or t->state == OFF or (t->tflags & (BROKEN | PBROKEN)) )
  652.         continue;
  653.  
  654.     if( n == t->source )
  655.       {
  656.         other = t->drain;    pcache = &(t->dcache.r);
  657.       }
  658.     else
  659.       {
  660.         other = t->source;    pcache = &(t->scache.r);
  661.       }
  662.  
  663.     /*
  664.      * if cache is not empty use the value found there, otherwise
  665.      * compute what is on the other side of the transistor and 
  666.      * transmit the result through a series operation.
  667.      */
  668.     if( (cache = *pcache) == NULL )
  669.       {
  670.         cache = series_op( get_dc_val( other, t, level+inc_level ), t );
  671.         *pcache = cache;
  672.       }
  673.     parallel_op( r, cache );
  674.       }
  675.  
  676.     if( n->nflags & USERDELAY )        /* record user delays, if any */
  677.       {
  678.     r->tplh = n->tplh; r->tphl = n->tphl;
  679.     r->flags |= T_UDELAY;
  680.       }
  681.  
  682.     if( level != 0 )
  683.     print_dc( n, r, level );
  684.  
  685.     return( r );
  686.   }
  687.  
  688.  
  689. /*
  690.  * The following macros set Req to the appropriate dynamic resistance.
  691.  * If the transistor state is UNKNOWN then also set the T_XTRAN flag.
  692.  */
  693. #define    GetReq( R, T, TYPE )            \
  694.   {                        \
  695.     if( ( (T)->tflags & PARALLEL ) )        \
  696.     get_parallel( R, T, TYPE );        \
  697.     else                    \
  698.       {                        \
  699.     (R)->Req.min = (T)->r->dynres[TYPE];    \
  700.     if( (T)->state == UNKNOWN )        \
  701.         (R)->flags |= T_XTRAN;        \
  702.     else                    \
  703.         (R)->Req.max = (T)->r->dynres[TYPE];\
  704.       }                        \
  705.   }                        \
  706.  
  707.  
  708. #define    GetMinR( R, T )                \
  709.   {                        \
  710.     if( ( (T)->tflags & PARALLEL ) )        \
  711.     get_min_parallel( R, T );        \
  712.     else                    \
  713.       {                        \
  714.     (R)->Req.min = MIN( (T)->r->dynhigh, (T)->r->dynlow );    \
  715.     if( (T)->state == UNKNOWN )        \
  716.         (R)->flags |= T_XTRAN;        \
  717.     else                    \
  718.         (R)->Req.max = (R)->Req.min;    \
  719.       }                        \
  720.   }                        \
  721.  
  722. /*
  723.  * Do the same as GetReq but deal with parallel transistors.
  724.  */
  725. private void get_parallel( r, t, restype )
  726.   Thev           r;
  727.   register tptr  t;
  728.   int            restype;
  729.   {
  730.     register Resists  *rp = t->r;
  731.     double            gmin, gmax;
  732.  
  733.     gmin = 1.0 / rp->dynres[ restype ];
  734.     gmax = (t->state == UNKNOWN ) ? 0.0 : gmin;
  735.  
  736.     for( t = par_list( t ); t != NULL; t = t->dcache.t )
  737.       {
  738.     rp = t->r;
  739.     gmin += 1.0 / rp->dynres[ restype ];
  740.     if( t->state != UNKNOWN )
  741.         gmax += 1.0 / rp->dynres[ restype ];
  742.       }
  743.     r->Req.min = 1.0 / gmin;
  744.     if( gmax == 0.0 )
  745.     r->flags |= T_XTRAN;
  746.     else
  747.     r->Req.max = 1.0 / gmax;
  748.   }
  749.  
  750.  
  751. /*
  752.  * Do the same as get_parallel but use the minimum dynamic resistance.
  753.  */
  754. get_min_parallel( r, t )
  755.   Thev           r;
  756.   register tptr  t;
  757.   {
  758.     register Resists  *rp = t->r;
  759.     double            gmin, gmax, tmp;
  760.  
  761.     gmin = 1.0 / MIN( rp->dynlow, rp->dynhigh );
  762.     gmax = (t->state == UNKNOWN ) ? 0.0 : gmin;
  763.  
  764.     for( t = par_list( t ); t != NULL; t = t->dcache.t )
  765.       {
  766.     rp = t->r;
  767.     tmp = 1.0 / MIN( rp->dynlow, rp->dynhigh );
  768.     gmin += tmp;
  769.     if( t->state != UNKNOWN )
  770.         gmax += tmp;
  771.       }
  772.     r->Req.min = 1.0 / gmin;
  773.     if( gmax == 0.0 )
  774.     r->flags |= T_XTRAN;
  775.     else
  776.     r->Req.max = 1.0 / gmax;
  777.   }
  778.  
  779.  
  780. /*
  781.  * Add transistor 't' in series with thevenin struct 'r'.  As a side effect
  782.  * set Req for 't'.  The midpoint voltage is used to determine whether to
  783.  * use the dynamic-high or dynamic-low resistance.  If the branch connecting
  784.  * to 't' is not driven by an input then use the charge information.  The
  785.  * current estimates of both resistance or capacitance is used.
  786.  */
  787. private Thev series_op( r, t )
  788.   register Thev  r;
  789.   register tptr  t;
  790.   {
  791.     double  up_min, down_min;
  792.  
  793.     if( not (r->flags & T_DRIVEN) )
  794.       {
  795.     if( r->Chigh.min > r->Clow.max )
  796.         GetReq( r, t, R_HIGH )
  797.     else if( r->Chigh.max < r->Clow.min )
  798.         GetReq( r, t, R_LOW )
  799.     else
  800.         GetMinR( r, t )
  801.     return( r );        /* no driver, so just set Req */ 
  802.       }
  803.  
  804.     if( r->Rdown.min > r->Rup.max )
  805.     GetReq( r, t, R_HIGH )
  806.     else if( r->Rdown.max < r->Rup.min )
  807.     GetReq( r, t, R_LOW )
  808.     else
  809.     GetMinR( r, t )
  810.  
  811.     up_min = r->Rup.min;
  812.     down_min = r->Rdown.min;
  813.  
  814.     if( up_min < LIMIT )
  815.     r->Rup.min += r->Req.min * ( 1.0 + up_min / r->Rdown.max );
  816.     if( down_min < LIMIT )
  817.     r->Rdown.min += r->Req.min * ( 1.0 + down_min / r->Rup.max );
  818.     if( r->flags & T_XTRAN )
  819.       {
  820.     r->flags &= ~T_DEFINITE;
  821.     r->Rup.max = r->Rdown.max = LARGE;
  822.       }
  823.     else
  824.       {
  825.     if( r->Rup.max < LIMIT )
  826.         r->Rup.max += r->Req.max * ( 1.0 + r->Rup.max / down_min );
  827.     if( r->Rdown.max < LIMIT )
  828.         r->Rdown.max += r->Req.max * ( 1.0 + r->Rdown.max / up_min );
  829.       }
  830.     return( r );
  831.   }
  832.  
  833.  
  834. /* make oldr = (oldr || newr), but watch out for infinte resistances. */
  835. #define    DoParallel( oldr, newr )    \
  836.   {                    \
  837.     if( oldr > LIMIT )            \
  838.     oldr = newr;            \
  839.     else if( newr < LIMIT )        \
  840.     oldr = COMBINE( oldr, newr );    \
  841.   }                    \
  842.  
  843.  
  844. /*
  845.  * Combine the new resistance block of the tree walk with the current one.
  846.  * Accumulate the low and high capacitances, the user-specified
  847.  * delay (if any), and the driven flag of the resulting structure.
  848.  */
  849. private void parallel_op( r, new )
  850.   Thev  r, new;
  851.   {
  852.     r->Clow.max += new->Clow.max;
  853.     r->Chigh.max += new->Chigh.max;
  854.     if( not (new->flags & T_XTRAN) )
  855.       {
  856.     r->Clow.min += new->Clow.min;
  857.     r->Chigh.min += new->Chigh.min;
  858.       }
  859.  
  860.     /*
  861.      * Accumulate the minimum user-specified delay only if the new block
  862.      * has some drive associated with it.
  863.      */
  864.     if( (new->flags & (T_DEFINITE | T_UDELAY)) == (T_DEFINITE | T_UDELAY) )
  865.      {
  866.     if( r->flags & T_UDELAY )
  867.       {
  868.         r->tplh = MIN( r->tplh, new->tplh );
  869.         r->tphl = MIN( r->tphl, new->tphl );
  870.       }
  871.     else
  872.       {
  873.         r->tplh = new->tplh;
  874.         r->tphl = new->tphl;
  875.         r->flags |= T_UDELAY;
  876.       }
  877.      }
  878.  
  879.     if( not (new->flags & T_DRIVEN) )
  880.     return;                /* undriven, just update caps */
  881.  
  882.     r->flags |= T_DRIVEN;        /* combined result is driven */
  883.  
  884.     DoParallel( r->Rup.min, new->Rup.min );
  885.     DoParallel( r->Rdown.min, new->Rdown.min );
  886.  
  887.     if( r->flags & new->flags & T_DEFINITE )    /* both definite blocks */
  888.       {
  889.     DoParallel( r->Rup.max, new->Rup.max );
  890.     DoParallel( r->Rdown.max, new->Rdown.max );
  891.       }
  892.     else if( new->flags & T_DEFINITE )        /* only new is definite */
  893.       {
  894.     r->Rup.max = new->Rup.max;
  895.     r->Rdown.max = new->Rdown.max;
  896.     r->flags |= T_DEFINITE;                /* result is definite */
  897.       }
  898.     else                /* new (perhaps r) is indefinite */
  899.       {
  900.     if( new->Rup.max < r->Rup.max )    r->Rup.max = new->Rup.max;
  901.     if( new->Rdown.max < r->Rdown.max ) r->Rdown.max = new->Rdown.max;
  902.       }
  903.   }
  904.  
  905.  
  906. /*
  907.  * Determine the input time-constant (input-slope * rstatic).  We are only
  908.  * interseted in transistors that just turned on (its gate has a transition
  909.  * at time == cur_delta).  We must be careful not to report as a transition
  910.  * nodes that stop being inputs (hist->delay == 0 and hist->inp == 0).
  911.  */
  912. #define IsCurrTransition( H )            \
  913.   ( (H)->time == cur_delta and ((H)->inp == 1 or (H)->t.r.delay != 0) )
  914.  
  915. /*
  916.  * Return TRUE if we should consider the input slope of this transistor.  As
  917.  * a side-effect, return the input time constant in 'ptin'.
  918.  */
  919. private int GetTin( t, ptin )
  920.   register tptr  t;
  921.   double         *ptin;
  922.   {
  923.     register hptr  h;
  924.     int            is_int = FALSE;
  925.  
  926.     if( t->state != ON )
  927.     return( FALSE );
  928.  
  929.     if( (t->ttype & GATELIST) == 0 )
  930.       {
  931.     h = t->gate->curr;
  932.     if( IsCurrTransition( h ) )
  933.       {
  934.         *ptin = h->t.r.rtime * t->r->rstatic;
  935.         is_int = TRUE;
  936.       }
  937.       }
  938.     else
  939.       {
  940.     double  tmp = 0.0;
  941.  
  942.     for( t = (tptr) t->gate; t != NULL; t = t->scache.t )
  943.       {
  944.         h = t->gate->curr;
  945.         if( IsCurrTransition( h ) )
  946.           {
  947.         is_int = TRUE;
  948.         tmp += h->t.r.rtime * t->r->rstatic;
  949.           }
  950.       }
  951.     *ptin = tmp;
  952.       }
  953.     return( is_int );
  954.   }
  955.  
  956. #define    InputTau( T, PR )    \
  957.   ( ((T)->tflags & PARALLEL) ? parallel_GetTin( T, PR ) : GetTin( T, PR ) )
  958.  
  959. private int parallel_GetTin( t, itau )
  960.   register tptr  t;
  961.   double         *itau;
  962.   {
  963.     double  tin, tmp = 0.0;
  964.     int     is_int;
  965.  
  966.     is_int = GetTin( t, &tin );
  967.  
  968.     for( t = par_list( t ); t != NULL; t = t->dcache.t )
  969.       {
  970.     if( GetTin( t, &tmp ) )
  971.       {
  972.         tin = (is_int) ? COMBINE_R( tin, tmp ) : tmp;
  973.         is_int = TRUE;
  974.       }
  975.     *itau = tin;
  976.       }
  977.     return( is_int );
  978.   }
  979.  
  980.  
  981. /*
  982.  * Compute the parameters needed to calculate the 1st order time-constants
  983.  * (Rmin, Rdom, Rmax, Ca, Cd, Tin) by doing a depth-first traversal of the
  984.  * tree rooted at node 'n'.  The parameters are gathered by performing a
  985.  * recursive tree walk similar to ComputeDC.  As a side effect, the tauP
  986.  * field will contain the multiplication factor to move a capacitor across
  987.  * a transistor using 'current distribution', this field may be required
  988.  * later when computing tauP.  The parameters are:
  989.  *
  990.  * n      : the node whose time-constant parameters we want.
  991.  * dom    : the value of the dominant driver for this stage.
  992.  * tran   : the transistor that leads to 'n' (NULL if none).
  993.  * level  : level of recursion if we are debugging this node, else 0.
  994.  *
  995.  * This routine can be called more than once if the stage is dominated by
  996.  * more than 1 potential, hence the tau_done flag keeps track of the potential
  997.  * for which the parameters stored in the cache were computed.  If the flag
  998.  * value and the current dominant potential do not match, we go ahead and
  999.  * recompute the values.
  1000.  */
  1001. private Thev get_tau( n, tran, dom, level )
  1002.   nptr  n;
  1003.   tptr  tran;
  1004.   int   dom;
  1005.   int   level;
  1006.   {
  1007.     register Thev  r, cache;
  1008.     register lptr  l;
  1009.     register tptr  t;
  1010.     register nptr  other;
  1011.  
  1012.     if( tran == NULL )
  1013.     r = n->n.thev;
  1014.     else
  1015.     r = (tran->source == n) ? tran->scache.r : tran->dcache.r;
  1016.  
  1017.     r->tau_done = dom;
  1018.  
  1019.     if( n->nflags & INPUT )
  1020.       {
  1021.     r->Tin = r->Rmin = r->Ca = r->Cd = 0.0;
  1022.     if( n->npot == dom )
  1023.       {
  1024.         r->Rdom = r->Rmax = 0.0;
  1025.         r->flags |= T_DOMDRIVEN;
  1026.       }
  1027.     else
  1028.       {
  1029.         r->flags &= ~(T_DOMDRIVEN | T_INT);
  1030.         if( dom == X )
  1031.         r->Rdom = r->Rmax = 0.0;
  1032.         else
  1033.         r->Rdom = r->Rmax = LARGE;
  1034.       }
  1035.     return( r );
  1036.       }
  1037.  
  1038.     if( n->n.thev->flags & T_REFNODE )        /* reference node in pure CS */
  1039.       {
  1040.     r->Rmin = r->Rdom = r->Rmax = 0.0;
  1041.     r->Ca = r->Cd = 0.0;
  1042.     return( r );
  1043.       }
  1044.  
  1045.     r->Rmin = r->Rdom = r->Rmax = LARGE;
  1046.     r->Cd = n->ncap;
  1047.     if( dom == X )            /* assume X nodes are charged high */
  1048.     r->Ca = (n->npot == LOW) ? 0.0 : n->ncap;
  1049.     else
  1050.     r->Ca = (n->npot == dom) ? 0.0 : n->ncap;
  1051.  
  1052.     r->Tin = 0.0;
  1053.     r->flags &= ~(T_DOMDRIVEN | T_INT);
  1054.  
  1055.     for( l = n->nterm; l != NULL; l = l->next )
  1056.       {
  1057.     t = l->xtor;
  1058.     if( t->state == OFF or t == tran or (t->tflags & (BROKEN | PBROKEN)) )
  1059.         continue;
  1060.  
  1061.     if( n == t->source )
  1062.       {
  1063.         other = t->drain;    cache = t->dcache.r;
  1064.       }
  1065.     else
  1066.       {
  1067.         other = t->source;    cache = t->scache.r;
  1068.       }
  1069.  
  1070.     if( cache->tau_done != dom )
  1071.       {
  1072.         double  oldr;
  1073.  
  1074.         cache = get_tau( other, t, dom, level + inc_level );
  1075.         /* Only use input slope for xtors on the dominant (driven) path */
  1076.         if( (cache->flags & T_DOMDRIVEN) and InputTau( t, &oldr ) )
  1077.           {
  1078.         cache->flags |= T_INT;
  1079.         cache->Tin += oldr;
  1080.           }
  1081.  
  1082.         oldr = cache->Rdom;
  1083.  
  1084.         cache->Rmin += cache->Req.min;
  1085.         cache->Rdom += cache->Req.min;
  1086.         if( cache->flags & T_XTRAN )
  1087.         cache->Rmax = LARGE;
  1088.         else
  1089.         cache->Rmax += cache->Req.max;
  1090.  
  1091.         /* Exclude capacitors if the other side of X transistor == dom */
  1092.         if( (cache->flags & T_XTRAN) and other->npot == dom )
  1093.         cache->tauP = cache->Ca = cache->Cd = 0.0;
  1094.         else if( oldr > LIMIT )
  1095.         cache->tauP = 1.0;
  1096.         else
  1097.           {
  1098.         cache->tauP = oldr / cache->Rdom;
  1099.         cache->Ca *= cache->tauP;
  1100.         cache->Cd *= cache->tauP;
  1101.           }
  1102.       }
  1103.  
  1104.     r->Ca += cache->Ca;
  1105.     r->Cd += cache->Cd;
  1106.  
  1107.     r->Rmin = COMBINE( r->Rmin, cache->Rmin );
  1108.     if( r->Rdom > LIMIT )
  1109.       {
  1110.         r->Rdom = cache->Rdom;
  1111.         r->Rmax = cache->Rmax;
  1112.       }
  1113.     else if( cache->Rdom < LIMIT )
  1114.       {
  1115.         r->Rdom = COMBINE( r->Rdom, cache->Rdom );
  1116.         r->Rmax = COMBINE( r->Rmax, cache->Rmax );
  1117.       }
  1118.  
  1119.     if( cache->flags & T_DOMDRIVEN )
  1120.         r->flags |= T_DOMDRIVEN;    /* at least 1 dominant driven path */
  1121.  
  1122.     if( cache->flags & T_INT )
  1123.       {
  1124.         if( r->flags & T_INT )
  1125.         r->Tin = COMBINE_R( r->Tin, cache->Tin );
  1126.         else
  1127.           {
  1128.         r->Tin = cache->Tin;
  1129.         r->flags |= T_INT;
  1130.           }
  1131.       }
  1132.       }
  1133.  
  1134.     if( level > 0 )
  1135.     print_tau( n, r, level );
  1136.  
  1137.     return( r );
  1138.   }
  1139.  
  1140.  
  1141. /*
  1142.  * Calculate the 2nd order time constant (tauP) for the net configuration
  1143.  * as seen through node 'n'.  The net traversal and the parameters are
  1144.  * similar to 'get_tau'.  Note that at this point we have not have calculated
  1145.  * tauA for nodes not driven to the dominant potential, hence we need to
  1146.  * compute those by first calling get_tau.  This routine will update the tauP
  1147.  * entry as well as the taup_done flag.
  1148.  */
  1149. private double get_tauP( n, tran, dom, level )
  1150.   nptr  n;
  1151.   tptr  tran;
  1152.   int   dom;
  1153.   int   level;
  1154.   {
  1155.     register lptr  l;
  1156.     register tptr  t;
  1157.     register Thev  r;
  1158.     nptr           other;
  1159.     double         taup;
  1160.  
  1161.     if( n->nflags & INPUT )
  1162.     return( 0.0 );
  1163.  
  1164.     r = n->n.thev;
  1165.     if( r->tau_done != dom )        /* compute tauA for the node */
  1166.       {
  1167.     r = get_tau( n, (tptr) NULL, dom, 0 );
  1168.     r->tauA = r->Rdom * r->Ca;
  1169.     r->tauD = r->Rdom * r->Cd;
  1170.       }
  1171.  
  1172.     taup = r->tauA * n->ncap;
  1173.  
  1174.     for( l = n->nterm; l != NULL; l = l->next )
  1175.       {
  1176.     t = l->xtor;
  1177.     if( t->state == OFF or t == tran or (t->tflags & (BROKEN | PBROKEN)) )
  1178.         continue;
  1179.  
  1180.     if( t->source == n )
  1181.         other = t->drain,    r = t->dcache.r;
  1182.     else
  1183.         other = t->source,    r = t->scache.r;
  1184.  
  1185.     if( r->taup_done != dom )
  1186.       {
  1187.         r->tauP *= get_tauP( other, t, dom, level + inc_level );
  1188.         r->taup_done = dom;
  1189.       }
  1190.     taup += r->tauP;
  1191.       }
  1192.     if( level > 0 )
  1193.     print_taup( n, level, taup );
  1194.  
  1195.     return( taup );
  1196.   }
  1197.  
  1198.  
  1199. #include "spiketbl.c"
  1200.  
  1201. /*
  1202.  * Compute the size of spike.  If the spike is too small return NULL, else
  1203.  * fill in the appropriate structure and return a pointer to it.  In order
  1204.  * to determine in which table to lookup the spike peak we look at the
  1205.  * conductivity of all ON transistors connected to node 'nd'; the type with
  1206.  * the largest conductivity determines whether it is mostly an nmos or pmos
  1207.  * network.  This simple scheme should work for most simple nets.
  1208.  */
  1209. private pspk ComputeSpike( nd, r, dom )
  1210.   nptr           nd;
  1211.   register Thev  r;
  1212.   int            dom;
  1213.   {
  1214.     int              rtype, tab_indx, alpha, beta, N;
  1215.     float            nmos, pmos;
  1216.     static SpikeRec  spk;
  1217.     register lptr    l;
  1218.  
  1219.     if( r->tauP <= SMALL )        /* no capacitance, no spike */
  1220.       {
  1221.     if( (debug & DEBUG_SPK) and IsWatched( nd ) )
  1222.         lprintf( stdout, " spike( %s ) ignored (taup=0)\n" );
  1223.     return( NULL );
  1224.       }
  1225.  
  1226.     rtype = (dom == LOW) ? R_LOW : R_HIGH;
  1227.     nmos = pmos = 0;
  1228.     for( l = nd->nterm; l != NULL; l = l->next )
  1229.       {
  1230.     register tptr  t;
  1231.  
  1232.     t = l->xtor;
  1233.     if( t->state == OFF or (t->tflags & BROKEN) )
  1234.         continue;
  1235.     if( BASETYPE( t->ttype ) == PCHAN )
  1236.         pmos += 1.0 / t->r->dynres[ rtype ];
  1237.     else
  1238.         nmos += 1.0 / t->r->dynres[ rtype ];
  1239.       }
  1240.     if( nmos > NP_RATIO * (pmos + nmos) )        /* mostly nmos */
  1241.     tab_indx = (rtype == R_LOW) ? NLSPKMIN : NLSPKMAX;
  1242.     else if( pmos > NP_RATIO * (pmos + nmos) )        /* mostly pmos */
  1243.     tab_indx = (rtype == R_LOW) ? NLSPKMAX : NLSPKMIN;
  1244.     else
  1245.     tab_indx = LINEARSPK;
  1246.  
  1247.     alpha = (int) ( SPIKETBLSIZE * r->tauA / (r->tauA + r->tauP - r->tauD) );
  1248.     if( alpha < 0 )
  1249.     alpha = 0;
  1250.     else if( alpha > SPIKETBLSIZE )
  1251.     alpha = SPIKETBLSIZE;
  1252.  
  1253.     beta = (int) ( SPIKETBLSIZE * (r->tauD - r->tauA) / r->tauD );
  1254.     if( beta < 0 )
  1255.     beta = 0;
  1256.     else if( beta > SPIKETBLSIZE )
  1257.     beta = SPIKETBLSIZE;
  1258.  
  1259.     spk.peak = spikeTable[ tab_indx ][ beta ][ alpha ];
  1260.     spk.ch_delay = delayTable[ beta ][ alpha ];
  1261.  
  1262.     if( dom == LOW )
  1263.       {
  1264.     if( spk.peak <= nd->vlow )        /* spike is too small */
  1265.         goto no_spike;
  1266.     else
  1267.         spk.charge = (spk.peak >= nd->vhigh) ? HIGH : X;
  1268.       }
  1269.     else    /* dom == HIGH */
  1270.       {
  1271.     if( spk.peak <= 1.0 - nd->vhigh )
  1272.         goto no_spike;
  1273.     else
  1274.         spk.charge = (spk.peak >= 1.0 - nd->vlow) ? LOW : X;
  1275.       }
  1276.  
  1277.     spk.ch_delay *= r->tauA * r->tauD / r->tauP;
  1278.  
  1279.     if( r->Rmax < LARGE )
  1280.     spk.dr_delay = r->Rmax * r->Ca;
  1281.     else
  1282.     spk.dr_delay = r->Rdom * r->Ca;
  1283.  
  1284.     if( (debug & DEBUG_SPK) and IsWatched( nd ) )
  1285.     print_spk( nd, r, tab_indx, dom, alpha, beta, &spk, TRUE );
  1286.     return( &spk );
  1287.  
  1288.   no_spike :
  1289.     if( (debug & DEBUG_SPK) and IsWatched( nd ) )
  1290.     print_spk( nd, r, tab_indx, dom, alpha, beta, &spk, FALSE );
  1291.     return( NULL );
  1292.   }
  1293.  
  1294.  
  1295. /*
  1296.  * Initialize pre-initialized thevenin structs.  I want to get it right
  1297.  * and this is much safer than letting the compiler initialize it.
  1298.  */
  1299. public void InitThevs()
  1300.   {
  1301.     register Thev  t;
  1302.  
  1303.     init_thev.link.n    = NULL;
  1304.     init_thev.flags    = 0;
  1305.     init_thev.Clow.min    = 0.0;
  1306.     init_thev.Clow.max    = 0.0;
  1307.     init_thev.Chigh.min    = 0.0;
  1308.     init_thev.Chigh.max    = 0.0;
  1309.     init_thev.Rup.min    = LARGE;
  1310.     init_thev.Rup.max    = LARGE;
  1311.     init_thev.Rdown.min    = LARGE;
  1312.     init_thev.Rdown.max    = LARGE;
  1313.     init_thev.Req.min    = LARGE;
  1314.     init_thev.Req.max    = LARGE;
  1315.     init_thev.V.min    = 1.0;
  1316.     init_thev.V.max    = 0.0;
  1317.     init_thev.Rmin    = LARGE;
  1318.     init_thev.Rdom    = LARGE;
  1319.     init_thev.Rmax    = LARGE;
  1320.     init_thev.Ca    = 0.0;
  1321.     init_thev.Cd    = 0.0;
  1322.     init_thev.tauD    = 0.0;
  1323.     init_thev.tauA    = 0.0;
  1324.     init_thev.tauP    = 0.0;
  1325.     init_thev.Tin    = SMALL;
  1326.     init_thev.tplh    = 0;
  1327.     init_thev.tphl    = 0;
  1328.     init_thev.final    = X;
  1329.     init_thev.tau_done    = N_POTS;
  1330.     init_thev.taup_done    = N_POTS;
  1331.  
  1332.     t =    &input_thev[ LOW ];
  1333.     t->link.n        = NULL;
  1334.     t->flags        = T_DEFINITE | T_DRIVEN;
  1335.     t->Clow.min        = 0.0;
  1336.     t->Clow.max        = 0.0;
  1337.     t->Chigh.min    = 0.0;
  1338.     t->Chigh.max    = 0.0;
  1339.     t->Rup.min        = LARGE;
  1340.     t->Rup.max        = LARGE;
  1341.     t->Rdown.min    = SMALL;
  1342.     t->Rdown.max    = SMALL;
  1343.     t->Req.min        = LARGE;
  1344.     t->Req.max        = LARGE;
  1345.     t->V.min        = 0.0;
  1346.     t->V.max        = 0.0;
  1347.     t->Rmin        = SMALL;
  1348.     t->Rdom        = LARGE;
  1349.     t->Rmax        = LARGE;
  1350.     t->Ca        = 0.0;
  1351.     t->Cd        = 0.0;
  1352.     t->tauD        = 0.0;
  1353.     t->tauA        = 0.0;
  1354.     t->tauP        = 0.0;
  1355.     t->Tin        = SMALL;
  1356.     t->tplh        = 0;
  1357.     t->tphl        = 0;
  1358.     t->final        = LOW;
  1359.     t->tau_done        = N_POTS;
  1360.     t->taup_done    = N_POTS;
  1361.  
  1362.     t = &input_thev[ HIGH ];
  1363.     t->link.n        = NULL;
  1364.     t->flags        = T_DEFINITE | T_DRIVEN;
  1365.     t->Clow.min        = 0.0;
  1366.     t->Clow.max        = 0.0;
  1367.     t->Chigh.min    = 0.0;
  1368.     t->Chigh.max    = 0.0;
  1369.     t->Rup.min        = SMALL;
  1370.     t->Rup.max        = SMALL;
  1371.     t->Rdown.min    = LARGE;
  1372.     t->Rdown.max    = LARGE;
  1373.     t->Req.min        = LARGE;
  1374.     t->Req.max        = LARGE;
  1375.     t->V.min        = 1.0;
  1376.     t->V.max        = 1.0;
  1377.     t->Rmin        = SMALL;
  1378.     t->Rdom        = LARGE;
  1379.     t->Rmax        = LARGE;
  1380.     t->Ca        = 0.0;
  1381.     t->Cd        = 0.0;
  1382.     t->tauD        = 0.0;
  1383.     t->tauA        = 0.0;
  1384.     t->tauP        = 0.0;
  1385.     t->Tin        = SMALL;
  1386.     t->tplh        = 0;
  1387.     t->tphl        = 0;
  1388.     t->final        = HIGH;
  1389.     t->tau_done        = N_POTS;
  1390.     t->taup_done    = N_POTS;
  1391.  
  1392.     t = &input_thev[ X ];
  1393.     t->link.n        = NULL;
  1394.     t->flags        = T_DEFINITE | T_DRIVEN;
  1395.     t->Clow.min        = 0.0;
  1396.     t->Clow.max        = 0.0;
  1397.     t->Chigh.min    = 0.0;
  1398.     t->Chigh.max    = 0.0;
  1399.     t->Rup.min        = SMALL;
  1400.     t->Rup.max        = LARGE;
  1401.     t->Rdown.min    = SMALL;
  1402.     t->Rdown.max    = LARGE;
  1403.     t->Req.min        = LARGE;
  1404.     t->Req.max        = LARGE;
  1405.     t->V.min        = 1.0;
  1406.     t->V.max        = 0.0;
  1407.     t->Rmin        = SMALL;
  1408.     t->Rdom        = LARGE;
  1409.     t->Rmax        = LARGE;
  1410.     t->Ca        = 0.0;
  1411.     t->Cd        = 0.0;
  1412.     t->tauD        = 0.0;
  1413.     t->tauA        = 0.0;
  1414.     t->tauP        = 0.0;
  1415.     t->Tin        = SMALL;
  1416.     t->tplh        = 0;
  1417.     t->tphl        = 0;
  1418.     t->final        = X;
  1419.     t->tau_done        = N_POTS;
  1420.     t->taup_done    = N_POTS;
  1421.  
  1422.     input_thev[ X+1 ] = input_thev[ X ];
  1423.   }
  1424.  
  1425.  
  1426. /*
  1427.  * printing routines for debug mode
  1428.  */
  1429.  
  1430. private char *get_indent( i )
  1431.   int  i;
  1432.   {
  1433.     static char   indent[] = ".........................";
  1434.     static char   spaces[] = "                          ";
  1435.     static int    last_c = 0;
  1436.     int           c;
  1437.  
  1438.     if( i >= sizeof( indent ) )
  1439.     i = sizeof( indent ) - 1;
  1440.     else
  1441.     i++;
  1442.  
  1443.     indent[ i ] = '\0';
  1444.     lprintf( stdout, " %s", indent );
  1445.     indent[ i ] = ' ';
  1446.     spaces[ last_c ] = ' ';
  1447.     last_c = i + 1;
  1448.     spaces[ last_c ] = '\0';
  1449.     return( spaces );
  1450.   }
  1451.  
  1452.  
  1453. private char *r2ascii( s, r )
  1454.   char    *s;
  1455.   double  r;
  1456.   {
  1457.     if( r >= LIMIT )
  1458.     (void) strcpy( s, " - " );
  1459.     else if( r > 1.0 )
  1460.       {
  1461.     int  exp;
  1462.  
  1463.     for( exp = 0; r >= 1000.0; exp++, r *= 0.001 );
  1464.     (void) sprintf( s, "%.1f%c", r, " KMG"[ exp ] );
  1465.       }
  1466.     else
  1467.     (void) sprintf( s, "%g", r );
  1468.  
  1469.     return( s );
  1470.   }
  1471.  
  1472.  
  1473. private void print_dc( n, r, level )
  1474.   nptr  n;
  1475.   Thev  r;
  1476.   int   level;
  1477.   {
  1478.     char  cbuf[4][20];
  1479.     char  *indent;
  1480.  
  1481.     indent = get_indent( level );
  1482.     lprintf( stdout, "compute_dc( %s )\n%s", pnode( n ), indent );
  1483.  
  1484.     if( not withdriven )
  1485.     lprintf( stdout, "pure cs:" );
  1486.     else
  1487.     lprintf( stdout, "%sefinite", (r->flags & T_DEFINITE) ? "D" : "Ind");
  1488.  
  1489.     lprintf( stdout, "  Rup=[%s, %s]  Rdown=[%s, %s]\n",
  1490.       r2ascii( cbuf[0], r->Rup.min ), r2ascii( cbuf[1], r->Rup.max ),
  1491.       r2ascii( cbuf[2], r->Rdown.min ), r2ascii( cbuf[3], r->Rdown.max ) );
  1492.  
  1493.     lprintf( stdout, "%sClow=[%.2f, %.2f]  Chigh=[%.2f, %.2f]\n",
  1494.       indent, r->Clow.min, r->Clow.max, r->Chigh.min, r->Chigh.max );
  1495.   }
  1496.  
  1497.  
  1498. private void print_fval( n, r )
  1499.   nptr  n;
  1500.   Thev  r;
  1501.   {
  1502.     lprintf( stdout, " final_value( %s )  V=[%.2f, %.2f]  => %c",
  1503.       pnode( n ), r->V.min, r->V.max, vchars[ r->final ] );
  1504.     lprintf( stdout,  (r->flags & T_SPIKE) ? "  (spk)\n" : "\n" );
  1505.   }
  1506.  
  1507.  
  1508. private void print_tau( n, r, level )
  1509.   nptr  n;
  1510.   Thev  r;
  1511.   int   level;
  1512.   {
  1513.     char  cbuf[3][20];
  1514.     char  *indent;
  1515.  
  1516.     indent = get_indent( level );
  1517.     lprintf( stdout, "compute_tau( %s )\n%s", pnode( n ), indent );
  1518.  
  1519.     lprintf( stdout, "{Rmin=%s  Rdom=%s  Rmax=%s}",
  1520.       r2ascii( cbuf[0], r->Rmin ), r2ascii( cbuf[1], r->Rdom ),
  1521.       r2ascii( cbuf[2], r->Rmax ) );
  1522.  
  1523.     lprintf( stdout, "  {Ca=%.2f  Cd=%.2f}\n", r->Ca, r->Cd );
  1524.  
  1525.     lprintf( stdout, "%stauA=%.1f  tauD=%.1f ns, RTin=",
  1526.       indent, ps2ns( r->Rdom * r->Ca ), ps2ns( r->Rdom * r->Cd ) );
  1527.  
  1528.     if( r->flags & T_INT )
  1529.     lprintf( stdout, "%.1f ohm*ns\n", d2ns( r->Tin ) );
  1530.     else
  1531.     lprintf( stdout, "-\n" );
  1532.   }
  1533.  
  1534.  
  1535. private void print_taup( n, level, taup )
  1536.   nptr    n;
  1537.   int     level;
  1538.   double  taup;
  1539.   {
  1540.     (void) get_indent( level );
  1541.     lprintf( stdout, "tauP( %s ) = %.1f ns\n", pnode( n ), ps2ns( taup ) );
  1542.   }
  1543.  
  1544.  
  1545. private void print_final( nd, queued, tau, delay )
  1546.   nptr    nd;
  1547.   int     queued;
  1548.   double  tau;
  1549.   Ulong   delay;
  1550.   {
  1551.     Thev   r;
  1552.     Ulong  dtau;    /* tau in deltas */
  1553.  
  1554.     r = nd->n.thev;
  1555.     dtau = ps2d( tau );
  1556.  
  1557.     lprintf( stdout, " [event %s->%c @ %.1f] ",
  1558.       pnode( cur_node ), vchars[ cur_node->npot ], d2ns( cur_delta ) );
  1559.  
  1560.     lprintf( stdout, (queued ? "causes %stransition for" : "%sevaluates"), 
  1561.     (withdriven ? "" : "CS ") );
  1562.  
  1563.     lprintf( stdout, " %s: %c -> %c", pnode( nd ),
  1564.       vchars[ nd->npot ], vchars[ r->final ] );
  1565.     lprintf( stdout, " (tau=%.1fns, delay=%.1fns)\n",
  1566.       d2ns( dtau ), d2ns( delay ) );
  1567.   }
  1568.  
  1569.  
  1570. private void print_spike( nd, spk, ch_delay, dr_delay )
  1571.   nptr    nd;
  1572.   pspk    spk;
  1573.   Ulong   ch_delay, dr_delay;
  1574.   {
  1575.     lprintf( stdout, "  [event %s->%c @ %.1f] causes ",
  1576.       pnode( cur_node ), vchars[ cur_node->npot ], d2ns( cur_delta ) );
  1577.     if( dr_delay <= ch_delay )
  1578.     lprintf( stdout, "suppressed " );
  1579.  
  1580.     lprintf( stdout, "spike for %s: %c -> %c -> %c", pnode( nd ),
  1581.       vchars[ nd->npot ], vchars[ spk->charge ], vchars[ nd->npot ] );
  1582.     lprintf( stdout, " (peak=%.2f delay: ch=%.1fns, dr=%.1fns)\n",
  1583.       spk->peak, d2ns( ch_delay ), d2ns( dr_delay ) );
  1584.   }
  1585.  
  1586.  
  1587. private void print_spk( nd, r, tab, dom, alpha, beta, spk, is_spk )
  1588.   nptr  nd;
  1589.   Thev  r;
  1590.   int   tab, dom, alpha, beta;
  1591.   pspk  spk;
  1592.   int   is_spk;
  1593.   {
  1594.     char  *net_type;
  1595.  
  1596.     lprintf( stdout, " spike_analysis( %s ):", pnode( nd ) );
  1597.     if( tab == LINEARSPK )
  1598.     net_type = "n-p mix";
  1599.     else if( tab == NLSPKMIN )
  1600.     net_type = (dom == LOW) ? "nmos" : "pmos";
  1601.     else
  1602.     net_type = (dom == LOW) ? "pmos" : "nmos";
  1603.  
  1604.     lprintf( stdout, " %s driven %s\n",
  1605.        net_type, (dom == LOW) ? "low" : "high" );
  1606.     lprintf( stdout, "{tauA=%.1f  tauD=%.1f  tauP=%.1f} ns  ",
  1607.       ps2ns( r->tauA ), ps2ns( r->tauD ), ps2ns( r->tauP ) );
  1608.     lprintf( stdout, "alpha=%d  beta=%d => peak=%.2f",
  1609.       alpha, beta, spk->peak );
  1610.     if( is_spk )
  1611.     lprintf( stdout, " v=%c\n", vchars[ spk->charge ] );
  1612.     else
  1613.     lprintf( stdout, " (too small)\n" );
  1614.   }
  1615.